package com.fallenpanda.location.manager;

import android.app.Application;
import android.os.Bundle;
import android.util.Log;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeOption;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.fallenpanda.location.bean.MyLocation;

import java.util.Arrays;

/**
 * 百度 定位管理器
 * ============================================================================
 * 版权所有 2014 。
 *
 * @author fallenpanda
 *
 * @version 1.0 2014-12-04
 * ============================================================================
 */
public class BaiduLocationManager extends BaseLocationManager {

    private static final String TAG = "BaiduLocationManager";

    private static final Integer[] SUCCESS_CODE = {BDLocation.TypeGpsLocation, BDLocation.TypeNetWorkLocation, BDLocation.TypeOffLineLocation, BDLocation.TypeCacheLocation};
    private static final Integer[] SUCCESS_CODE_NETWORK = {BDLocation.TypeGpsLocation, BDLocation.TypeNetWorkLocation};

    private static final String PRODUCT_NAME = "LocationDemo";//产品线名称
    private static final String LOCATION_COORTYPE = "bd09ll";//位置信息类型
    private static final int MIN_INTERVAL = 1000;//最小定位间隔

    private Application mContext;
    private MainLocationListener listener;
    private LocationClient client;
    private LocationClientOption clientOption;
    private BDLocationListener locationListener;

    private MyLocation mLocation;
    private GeoCoder search;

    private int interval = 0;
    private boolean isNeedAddress = false;

    public BaiduLocationManager(Application context, MainLocationListener mainLocationListener) {
        mContext = context;
        listener = mainLocationListener;
        locationListener = new BaiduLocationListener();
        client = new LocationClient(context);
        clientOption = getHighAccuracyOption();
        client.setLocOption(clientOption);
        client.registerLocationListener(locationListener);

        SDKInitializer.initialize(context);//百度地图组件
    }

    /**
     * 返回高精度定位设置（同时使用网络定位和GPS定位，优先返回最高精度的定位结果）
     * 默认：定位一次，无地址信息
     *
     * @return LocationClientOption
     */
    private LocationClientOption getHighAccuracyOption(){
        LocationClientOption locationClientOption = new LocationClientOption();
        locationClientOption.setProdName(PRODUCT_NAME);//产品线名称
        locationClientOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//设置定位模式
        locationClientOption.setCoorType(LOCATION_COORTYPE);//返回的定位结果是百度经纬度,默认值gcj02
        locationClientOption.setScanSpan(interval);//小于1000则为一次定位
        locationClientOption.setIsNeedAddress(false);//地址信息
        return locationClientOption;
    }

    /**
     * 定位一次
     */
    public void getLocationOnce(boolean isNeedAddress){
        getLocation(MainLocationManager.MODEL_ONCE, 0, isNeedAddress);
    }

    /**
     * 定位多次（暂不支持返回地址信息）
     */
    public void getLocationAuto(int interval){
        getLocation(MainLocationManager.MODEL_AUTO, interval, false);
    }

    /**
     * 定位
     *
     * @param mode
     *         MainLocationManager.MODEL_ONCE
     *         MainLocationManager.MODEL_AUTO
     * @param interval 定位间隔
     */
    private void getLocation(int mode,int interval, boolean isNeedAddress){
        System.out.println(TAG+"|getLocation|"+mode+"|"+interval+"|"+isNeedAddress);
        if (client == null)
            return;
        switch (mode){
            case MainLocationManager.MODEL_ONCE:
                if(client.isStarted()){
                    client.requestLocation();
                }else{
                    updateLocationOptions(0, isNeedAddress);
                }
                break;
            case MainLocationManager.MODEL_AUTO:
                if(interval < MIN_INTERVAL) interval = MIN_INTERVAL;
                updateLocationOptions(interval, false);
                break;
            default:
                break;
        }
    }

    /**
     * 是否开启
     * @return boolean
     */
    public boolean isStarted(){
        return client!=null && client.isStarted();
    }

    /**
     * 开启
     */
    public void start(){
        System.out.println(TAG+"|start");
        if ((client == null) || (client.isStarted()))
            return;
        client.start();
        onProviderEnabled();
    }

    /**
     * 关闭
     */
    public void stop(){
        System.out.println(TAG+"|stop");
        if ((client == null) || (!client.isStarted()))
            return;
        client.stop();
        onProviderDisabled();
    }

    /**
     * 销毁
     */
    public void destroy() {
        System.out.println(TAG+"|destroy");
        if (client == null)
            return;
        stop();
        client.unRegisterLocationListener(locationListener);
    }

    @Override
    public void onLocationChanged(MyLocation location) {
        System.out.println(TAG+"|onLocationChanged|"+interval);
        System.out.println(TAG+"|onLocationChanged|"+clientOption.getScanSpan());
        if(clientOption!=null&&interval==0) stop();
        if ((listener != null) && (location != null))
            listener.onLocationChanged(location);
    }

    @Override
    public void onLocationFail() {
        if (listener == null)
            return;
        listener.onLocationFail(MainLocationManager.BAIDU_PROVIDER);
    }

    @Override
    public void onStatusChanged(int status, Bundle extras) {
        if (listener == null)
            return;
        listener.onStatusChanged(MainLocationManager.BAIDU_PROVIDER, status, extras);
    }

    @Override
    public void onProviderEnabled() {
        if (listener == null)
            return;
        listener.onProviderEnabled(MainLocationManager.BAIDU_PROVIDER);
    }

    @Override
    public void onProviderDisabled() {
        if (listener == null)
            return;
        listener.onProviderDisabled(MainLocationManager.BAIDU_PROVIDER);
    }

    @Override
    public void updateLocationOptions(int interval, boolean isNeedAddress) {
        System.out.println(TAG+"|updateLocationOptions|"+interval+"|"+isNeedAddress);
        stop();
        if(this.interval != interval) {
            this.interval = interval;
            clientOption.setScanSpan(interval);
        }
        if(this.isNeedAddress != isNeedAddress) {
            this.isNeedAddress = isNeedAddress;
        }
        client.setLocOption(clientOption);
        start();
    }

    private class BaiduLocationListener implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation location) {
            if ((location == null) || (location.getLatitude() == 0.0D) || (location.getLongitude() == 0.0D)){
                onLocationFail();
            }else{
                int errorCode = location.getLocType();
                if(Arrays.asList(SUCCESS_CODE).contains(errorCode)){
                    MyLocation localLocation = new MyLocation(MainLocationManager.BAIDU_PROVIDER);
                    localLocation.setmTime(System.currentTimeMillis());
                    localLocation.setmCoorType(LOCATION_COORTYPE);
                    localLocation.setmLongitude(location.getLongitude());
                    localLocation.setmLatitude(location.getLatitude());
                    if (location.hasRadius()){
                        localLocation.setmHasAccuracy(true);
                        localLocation.setmAccuracy(location.getRadius());
                    }
                    if (location.hasAltitude()){
                        localLocation.setmHasAltitude(true);
                        localLocation.setmAltitude(location.getAltitude());
                    }
                    if (location.getLocType() == BDLocation.TypeGpsLocation){
                        localLocation.setmHasSpeed(true);
                        localLocation.setmSpeed(location.getSpeed());
                    } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){
//                        localLocation.setmHasAddress(true);
//                        localLocation.setmAddress(location.getAddrStr());
//                        localLocation.setmProvince(location.getProvince());
//                        localLocation.setmCity(location.getCity());
//                        localLocation.setmDistrict(location.getDistrict());
                    }
                    if (Arrays.asList(SUCCESS_CODE_NETWORK).contains(errorCode)) {
                        if(isNeedAddress){
                            //地理位置反解析
                            mLocation = localLocation;
                            search = GeoCoder.newInstance();
                            search.setOnGetGeoCodeResultListener(searchlListener);
                            LatLng point = new LatLng(location.getLatitude(), location.getLongitude());
                            search.reverseGeoCode(new ReverseGeoCodeOption()
                                    .location(point));
                        }else{
                            onLocationChanged(localLocation);
                        }
                    }
                }else{
                    onLocationFail();
                }
            }

            StringBuffer sb = new StringBuffer(256);
            sb.append(" ");
            sb.append("\ntime : ");
            sb.append(location.getTime());
            sb.append("\nerror code : ");
            sb.append(location.getLocType());
            sb.append("\nlatitude : ");
            sb.append(location.getLatitude());
            sb.append("\nlontitude : ");
            sb.append(location.getLongitude());
            sb.append("\nradius : ");
            sb.append(location.getRadius());
            if (location.getLocType() == BDLocation.TypeGpsLocation){
                sb.append("\nTypeGpsLocation");
                sb.append("\nspeed : ");
                sb.append(location.getSpeed());
                sb.append("\nsatellite : ");
                sb.append(location.getSatelliteNumber());
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){
                sb.append("\nTypeNetWorkLocation");
//                sb.append("\naddr : ");
//                sb.append(location.getAddrStr());
            }
            sb.append("\nisNeedAddress : ");
            sb.append(isNeedAddress);
            Log.d(TAG, sb.toString());
        }
    }

    private OnGetGeoCoderResultListener searchlListener = new OnGetGeoCoderResultListener() {

        public void onGetGeoCodeResult(GeoCodeResult result) {
            if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
                //没有检索到结果
            } else {
                //获取地理编码结果
            }
            search.destroy();
        }

        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
            if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
                //没有找到检索结果
                onLocationFail();
            } else {
                //获取反向地理编码结果
                mLocation.setmHasAddress(true);
                mLocation.setmAddress(result.getAddress());
                mLocation.setmProvince(result.getAddressDetail().province);
                mLocation.setmCity(result.getAddressDetail().city);
                mLocation.setmDistrict(result.getAddressDetail().district);
                onLocationChanged(mLocation);

                StringBuffer sb = new StringBuffer(256);
                sb.append(" ");
                sb.append("\naddr : ");
                sb.append(result.getAddress());
                Log.d(TAG, sb.toString());
            }
            search.destroy();
        }

    };

}
